//	-------------------------------------------------------------------------------------
//	Defines used to get various windows messages, such as WM_WHEEL
//	-------------------------------------------------------------------------------------
#ifndef WINVER                // Allow use of features specific to Windows 95 and Windows NT 4 or later.
#define WINVER 0x0501         // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif

#ifndef _WIN32_WINNT        // Allow use of features specific to Windows NT 4 or later.
#define _WIN32_WINNT 0x0501        // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif                       

#ifndef _WIN32_WINDOWS        // Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0501 // Change this to the appropriate value to target Windows Me or later.
#endif 

//#define DEBUGMODE

//	-------------------------------------------------------------------------------------
//	Includes section
//	-------------------------------------------------------------------------------------
#include "stdafx.h"
#include <Windows.h>
#include <WinUser.h>
#include <mmsystem.h>
#include <d3dx9.h>
#include <conio.h>
#pragma warning( disable : 4996 ) // disable deprecated warning 
#include <strsafe.h>
#pragma warning( default : 4996 ) 
#include "DXSniffer.h"

//	-------------------------------------------------------------------------------------
//	Typedefs
//	-------------------------------------------------------------------------------------

// A structure for our custom vertex type. 
struct CUSTOMVERTEX
{
	FLOAT x, y, z;      // The untransformed, 3D position for the vertex
	DWORD color;        // The vertex color 
	D3DXVECTOR3 norm;   // the vertex normal
	FLOAT       tu, tv;   // The texture coordinates
	static DWORD const FVF;
};
const DWORD CUSTOMVERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_NORMAL;

//	-------------------------------------------------------------------------------------
// Global variables
//	-------------------------------------------------------------------------------------

//	Globals used to create the scene
LPDIRECT3D9             g_pD3D       = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL; // Buffer to hold vertexes 
LPDIRECT3DTEXTURE9      EarthTex   = NULL; // Our texture
LPDIRECT3DTEXTURE9      MoonTex   = NULL; // Our texture
LPDIRECT3DTEXTURE9      SunTex   = NULL; // Our texture

//	Meshes used in scene (3 Planets and camera's center)
ID3DXMesh* mesh1 = 0;	//	Sun
ID3DXMesh* mesh2 = 0;	//	Earth
ID3DXMesh* mesh3 = 0;	//	Moon
ID3DXMesh* mesh4 = 0;	//	Camera's Center

//	Mouse Globals used to track down dragging
int mouseX = 0, mouseY = 0;
int prevMouseX = 0, prevMouseY = 0;

//	Camera Position's vars
double camThetaAngle = 0.0;			//	XZ plane angle
double camPhiAngle = D3DX_PI / 2;	//	Angle from the Y axis
float camRadius = 100.0f;			//	Camera's sphere's radius
float camCenterX = 0.0, camCenterZ = 0.0;

//	Rendering window size
int WindowHeight = 256;
int WindowWidth = 256;

//	Which planet to wireframe
int WireFrame = 0; 
int MaxFrame = 3;    //one more than the final one 

//************************************************************************************************//
//******                                                                                    ******//
//******                          Function's Implementation                                 ******//
//******                                                                                    ******//
//************************************************************************************************//

//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
	// Create the D3D object.
	if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
		return E_FAIL;

	// Set up the structure used to create the D3DDevice. Since we are now
	// using more complex geometry, we will create a device with a zbuffer.
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof(d3dpp) );
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	// Create the D3DDevice
	if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		D3DCREATE_HARDWARE_VERTEXPROCESSING,
		&d3dpp, &g_pd3dDevice ) ) )
	{
		return E_FAIL;
	}

	// Turn off culling
	g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

	// Turn on the zbuffer
	g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

	g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

	return S_OK;
}


//-----------------------------------------------------------------------------
// Name: CreateMappedSphere()
// Desc: Draws textures on spheres
//-----------------------------------------------------------------------------
LPD3DXMESH CreateMappedSphere(LPDIRECT3DDEVICE9 pDev,float fRad,UINT slices,UINT stacks)
{
	// create the sphere
	LPD3DXMESH mesh;
	if (FAILED(D3DXCreateSphere(pDev,fRad,slices,stacks,&mesh,NULL)))
		return NULL;

	// create a copy of the mesh with texture coordinates,
	// since the D3DX function doesn't include them
	LPD3DXMESH texMesh;
	if (FAILED(mesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM,CUSTOMVERTEX::FVF,pDev,&texMesh)))
		// failed, return un-textured mesh
		return mesh;

	// finished with the original mesh, release it
	mesh->Release();

	// lock the vertex buffer
	CUSTOMVERTEX* pVerts;
	if (SUCCEEDED(texMesh->LockVertexBuffer(0,(VOID **) &pVerts))) {

		// get vertex count
		int numVerts=texMesh->GetNumVertices();

		// loop through the vertices
		for (int i=0;i<numVerts;i++) {

			//note to self: play a little with the coords
			// calculate texture coordinates
			pVerts->tu=asinf(pVerts->norm.y)/D3DX_PI+0.5f;
			pVerts->tv=asinf(pVerts->norm.x)/D3DX_PI+0.5f;

			// go to next vertex
			pVerts++;
		}

		// unlock the vertex buffer
		texMesh->UnlockVertexBuffer();
	}

	// return pointer to caller
	return texMesh;
}

//-----------------------------------------------------------------------------
// Name: InitGeometry()
// Desc: Creates the scene geometry
//-----------------------------------------------------------------------------
HRESULT InitGeometry()
{
	//Creating the Texture maps 

	// Use D3DX to create a texture from a file based image
	if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"Earth1.jpg", &EarthTex ) ) )
	{
		return E_FAIL;
	}
	if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"Moon1.jpg", &MoonTex ) ) )
	{
		return E_FAIL;
	}
	if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"Sun1.jpg", &SunTex ) ) )
	{
		return E_FAIL;
	}

	//	Creating the meshes

	mesh1=CreateMappedSphere(g_pd3dDevice,10,50,50);
	mesh2=CreateMappedSphere(g_pd3dDevice,5,50,50);
	mesh3=CreateMappedSphere(g_pd3dDevice,2,50,50);
	mesh4=CreateMappedSphere(g_pd3dDevice,1,10,10);

	// Initialize three vertexes for rendering the axes
	CUSTOMVERTEX g_Vertices[] =
	{
		{ 0.0f, 0.0f, 0.0f, 0xffff0000, },
		{ 100.0f, 0.0f, 0.0f, 0xffff0000, },
		{ 0.0f, 0.0f, 0.0f, 0xff00ff00, },
		{ 0.0f, 100.0f, 0.0f, 0xff00ff00, },
		{ 0.0f, 0.0f, 0.0f, 0xff0000ff, },
		{ 0.0f, 0.0f, 100.0f, 0xff0000ff, },
	};

	// Create the vertex buffer.
	if( FAILED( g_pd3dDevice->CreateVertexBuffer( 6*sizeof(CUSTOMVERTEX),
		0, CUSTOMVERTEX::FVF,
		D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
	{
		return E_FAIL;
	}

	// Fill the vertex buffer.
	VOID* pVertices;
	if( FAILED( g_pVB->Lock( 0, sizeof(g_Vertices), (void**)&pVertices, 0 ) ) )
		return E_FAIL;
	memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );
	g_pVB->Unlock();

	return S_OK;
}

//-----------------------------------------------------------------------------
// Name: CleanupResources()
// Desc: Releases all Scene's resources (to use before reset)
//-----------------------------------------------------------------------------
VOID CleanupResources()
{
	if( g_pVB != NULL )
	{
		g_pVB->Release();
		g_pVB = 0;
	}
	if (mesh1 != NULL)
	{
		mesh1->Release();
		mesh1 = 0;
	}
	if (mesh2 != NULL)
	{
		mesh2->Release();
		mesh2 = 0;
	}
	if (mesh3 != NULL)
	{
		mesh3->Release();
		mesh3 = 0;
	}
	if (mesh4 != NULL)
	{
		mesh4->Release();
		mesh4 = 0;
	}
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
	if( g_pd3dDevice != NULL )
	{
		g_pd3dDevice->Release();
		g_pd3dDevice = 0;
	}
	if( g_pD3D != NULL )
	{
		g_pD3D->Release();
		g_pD3D = 0;
	}

	CleanupResources();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//--------------               Camera's Functions             -----------------
//-----------------------------------------------------------------------------	
//-----------------------------------------------------------------------------
// Name: RotateCamera()
// Desc: Sets up the camera angles using spherical coordinates (theta is XZ plane
//		 angle and phi is the angle between the point and the Y axis)
//-----------------------------------------------------------------------------
void RotateCamera()
{
	float tmp = (float)mouseX - prevMouseX;
	if (tmp != 0)
	{
		camThetaAngle += tmp * D3DX_PI / 180;
		if (camThetaAngle > D3DX_PI - 0.1)
			camThetaAngle = D3DX_PI - 0.1;

		if (camThetaAngle < - D3DX_PI + 0.1)
			camThetaAngle = - D3DX_PI + 0.1;

	}
	tmp = (float)mouseY - prevMouseY;
	if (tmp != 0)
	{
		camPhiAngle += tmp * D3DX_PI / 180;
		if (camPhiAngle > D3DX_PI - 0.1)
			camPhiAngle = D3DX_PI - 0.1;

		if (camPhiAngle < 0.1)
			camPhiAngle = 0.1;
	}

#ifdef DEBUGMODE
	printf ("\nCamera Rotation is: Theta: %f, Phi: %f.",camThetaAngle, camPhiAngle);
#endif
}

//-----------------------------------------------------------------------------
// Name: MoveCamera()
// Desc: Sets up the camera's sphere center point
//-----------------------------------------------------------------------------
void MoveCamera()
{
	float tmp = (float)mouseX - prevMouseX;
	if (tmp != 0)
	{
		camCenterX += tmp;
		if (camCenterX > 500)
			camCenterX = 500;

		if (camCenterX < - 500)
			camCenterX = - 500;
	}
	tmp = (float)mouseY - prevMouseY;
	if (tmp != 0)
	{
		camCenterZ += tmp;
		if (camCenterZ > 500)
			camCenterZ = 500;

		if (camCenterZ < - 500)
			camCenterZ = - 500;
	}

#ifdef DEBUGMODE
	printf ("\nCamera Center is: (X,0,Z) = (%f, 0, %f)", camCenterX, camCenterZ);
#endif
}

//-----------------------------------------------------------------------------
// Name: SetupMatrices()
// Desc: Sets up the world, view, and projection transform matrices.
//-----------------------------------------------------------------------------
VOID SetupMatrices()
{
	// Set up our view matrix. A view matrix can be defined given an eye point,
	// a point to lookat, and a direction for which way is up. Here, we set the
	// eye five units back along the z-axis and up three units, look at the
	// origin, and define "up" to be in the y-direction.
	double x0, y0, z0;
	x0 = camRadius * sin(camThetaAngle) * sin(camPhiAngle) + camCenterX;
	y0 = camRadius * cos(camPhiAngle);
	z0 = camRadius * cos(camThetaAngle) * sin(camPhiAngle) + camCenterZ;
	D3DXVECTOR3 vEyePt( (float)x0, (float)y0, (float)z0 );
	D3DXVECTOR3 vLookatPt( camCenterX, 0.0f, camCenterZ );
	D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
	D3DXMATRIXA16 matView;
	D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
	g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

	// For the projection matrix, we set up a perspective transform (which
	// transforms geometry from 3D view space to 2D viewport space, with
	// a perspective divide making objects smaller in the distance). To build
	// a perpsective transform, we need the field of view (1/4 pi is common),
	// the aspect ratio, and the near and far clipping planes (which define at
	// what distances geometry should be no longer be rendered).
	D3DXMATRIXA16 matProj;
	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, (float) WindowWidth / WindowHeight, 1.0f, 1000.0f );
	g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//--------------           Lights Settings Functions          -----------------
//-----------------------------------------------------------------------------	
//-----------------------------------------------------------------------------
// Name: CreatePointLight(float x, float y, float z)
// Desc: Creates a light point centered in x,y,z.
//-----------------------------------------------------------------------------
VOID CreatePointLight(float x, float y, float z)
{
	static int i = 0; 
	D3DXVECTOR3 vecDir;
	D3DLIGHT9 light;
	ZeroMemory( &light, sizeof(D3DLIGHT9) );
	light.Type       = D3DLIGHT_POINT;
	light.Diffuse.r  = 1.0f;
	light.Diffuse.g  = 1.0f;
	light.Diffuse.b  = 1.0f; 
	vecDir = D3DXVECTOR3(cosf(timeGetTime()/350.0f),
		1.0f,
		sinf(timeGetTime()/350.0f) );
	D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
	light.Range       = 1000.0f;
	light.Position.x = x; 
	light.Position.y = y; 
	light.Position.z = z; 
	light.Attenuation0 = 1.0f; 
	g_pd3dDevice->SetLight( i, &light );
	g_pd3dDevice->LightEnable( i, TRUE ); 
	g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); 
	i++; 
}

//-----------------------------------------------------------------------------
// Name: SetupLights()
// Desc: Sets up the Lights and materials for the scene.
//-----------------------------------------------------------------------------
VOID SetupLights()
{
	// Set up a material. The material here just has the diffuse and ambient
	// colors set to yellow. Note that only one material can be used at a time.

	CreatePointLight(0,0,30); 
	CreatePointLight(0,0,-30); 
	CreatePointLight(30,0,0); 
	CreatePointLight(-30,0,0); 
	CreatePointLight(0,-30,0); 
	CreatePointLight(0,30,0); 

	// Finally, turn on some ambient light.
	g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 ); 
	g_pd3dDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, 4);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//--------------               Drawing Functions              -----------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Name: SetMaterial(float r, float g, float b, float a)
// Desc: Setting current material to be rgba (Diffuse + Ambiant)
//-----------------------------------------------------------------------------
void SetMaterial(float p_r, float p_g, float p_b, float p_a)
{
	D3DMATERIAL9 mtrl;
	ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
	mtrl.Diffuse.r = mtrl.Ambient.r = p_r;
	mtrl.Diffuse.g = mtrl.Ambient.g = p_g;
	mtrl.Diffuse.b = mtrl.Ambient.b = p_b;
	mtrl.Diffuse.a = mtrl.Ambient.a = p_a;
	g_pd3dDevice->SetMaterial( &mtrl );
}

//-----------------------------------------------------------------------------
// Name: DrawAxes()
// Desc: Draws XYZ Axes
//-----------------------------------------------------------------------------
void DrawAxes()
{
	//	Resetting world position
	D3DXMATRIXA16 matWorld;
	D3DXMatrixIdentity( &matWorld );
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

	//	Setting device to draw the g_pVB vertex buffer using CUSTOMVERTEX
	g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
	g_pd3dDevice->SetFVF( CUSTOMVERTEX::FVF );

	//	Y Axis
	// -------------------------------
	SetMaterial(0, 1, 0, 1);

#ifdef DEBUGMODE
	g_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 2, 1 );
#else
	//	Sniffer Capture DrawPrimitive Simulation
	DXSniffer::Instance()->DrawPrimitiveUsed(g_pd3dDevice, D3DPT_LINELIST, 2, 1);
#endif

	//	X Axis
	// -------------------------------
	SetMaterial(1, 0, 0, 1);

#ifdef DEBUGMODE
	g_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 0, 1 );
#else
	//	Sniffer Capture DrawPrimitive Simulation
	DXSniffer::Instance()->DrawPrimitiveUsed(g_pd3dDevice, D3DPT_LINELIST, 0, 1);
#endif

	//	Z Axis
	// -------------------------------
	SetMaterial(0, 0, 1, 1);

#ifdef DEBUGMODE
	g_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 4, 1 );
#else
	//	Sniffer Capture DrawPrimitive Simulation
	DXSniffer::Instance()->DrawPrimitiveUsed(g_pd3dDevice, D3DPT_LINELIST, 4, 1);
#endif


	//	Camera Center
	// -------------------------------
	SetMaterial(1, 1, 1, 1);
	D3DXMatrixTranslation(&matWorld, camCenterX, 0, camCenterZ);
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

#ifdef DEBUGMODE
	mesh4->DrawSubset(0);  
#else
	//	Sniffer Capture DrawSubset Simulation
	DXSniffer::Instance()->DrawSubsetUsed(mesh4, 0);
#endif
}

//-----------------------------------------------------------------------------
// Name: Moon() Earth() Sun()
// Desc: Sets up the Material and location of each planet and draws them
//-----------------------------------------------------------------------------
VOID Moon() 
{
	SetMaterial(1, 1, 1, 1);

	//	Transformations
	D3DXMATRIXA16 matWorld1;
	D3DXMATRIXA16 matWorld2; 
	D3DXMATRIXA16 matWorld3; 
	D3DXMATRIXA16 matWorld4;  
	D3DXMatrixIdentity( &matWorld1 );
	D3DXMatrixRotationY( &matWorld1, timeGetTime()/1000.0f ); 
	D3DXMatrixTranslation(&matWorld2, 0.0f, 0.0f, 50.0f);
	D3DXMatrixRotationY( &matWorld3, timeGetTime()/250.0f ); 
	D3DXMatrixTranslation(&matWorld4, 0.0f, 0.0f, 8.0f);
	matWorld1 = matWorld4*matWorld3*matWorld2*matWorld1; 
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld1 );

	//	Choosing fill mode according to up & down arrows pressed
	if (WireFrame == 2) 
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	else 
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DRS_FILLMODE);

	g_pd3dDevice->SetTexture(0,MoonTex); //making it moon like

#ifdef DEBUGMODE
	mesh3->DrawSubset(0);  
#else
	//	Sniffer Capture DrawSubset Simulation
	DXSniffer::Instance()->DrawSubsetUsed(mesh3, 0);
#endif
}

VOID Earth()
{
	SetMaterial(1, 1, 1, 1);

	//	Transformations
	D3DXMATRIXA16 matWorld1;
	D3DXMATRIXA16 matWorld2; 
	D3DXMATRIXA16 matWorld3; 
	D3DXMatrixIdentity( &matWorld1 );
	D3DXMatrixRotationY( &matWorld1, timeGetTime()/1000.0f ); 
	D3DXMatrixTranslation(&matWorld2, 0.0f, 0.0f, 50.0f);
	D3DXMatrixRotationY( &matWorld3, timeGetTime()/5000.0f ); 
	matWorld1 = matWorld3*matWorld2*matWorld1; 
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld1 ); 

	//	Choosing fill mode according to up & down arrows pressed
	if (WireFrame == 1) 
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	else 
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DRS_FILLMODE);
	//making it earth like
	g_pd3dDevice->SetTexture(0,EarthTex);

#ifdef DEBUGMODE
	mesh2->DrawSubset(0);  
#else
	//	Sniffer Capture DrawSubset Simulation
	DXSniffer::Instance()->DrawSubsetUsed(mesh2, 0);
#endif
}

VOID Sun()
{
	SetMaterial(1, 0.6f, 0, 1);

	//	Transformations
	D3DXMATRIXA16 matWorld;
	D3DXMatrixIdentity( &matWorld );
	D3DXMatrixRotationY( &matWorld, timeGetTime()/500.0f );
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

	//	Choosing fill mode according to up & down arrows pressed
	if (WireFrame == 3) 
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	else 
		g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DRS_FILLMODE);

	g_pd3dDevice->SetTexture(0,SunTex);

#ifdef DEBUGMODE
	mesh1->DrawSubset(0);  
#else
	//	Sniffer Capture DrawSubset Simulation
	DXSniffer::Instance()->DrawSubsetUsed(mesh1, 0);
#endif
}

//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
	// Clear the backbuffer and the zbuffer
	g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
		D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); 

	// Begin the scene
	if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
	{
		// Setup the Lights and materials
		SetupLights();

		// Setup the world, view, and projection matrices
		SetupMatrices();

		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
		g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );

		//	Drawing Scene
		DrawAxes();
		Sun(); 
		Earth(); 
		Moon(); 

		// End the scene
		g_pd3dDevice->EndScene();
	}

	// Present the backbuffer contents to the display
#ifdef DEBUGMODE
	g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
#else
	//	Sniffer Capture Present Simulation
	DXSniffer::Instance()->PresentUsed(g_pd3dDevice, NULL, NULL, NULL, NULL);
#endif
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//--------------            Windows messages handlers         -----------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Name: OnDestroy()
// Desc: Callback function called when destroy message is received
//-----------------------------------------------------------------------------
void OnDestroy()
{
	Cleanup();
	PostQuitMessage( 0 );
}

//-----------------------------------------------------------------------------
// Name: OnSize()
// Desc: Callback function called when window is resized
//-----------------------------------------------------------------------------
void OnSize(HWND hWnd, LPARAM lParam)
{
	WindowWidth  = LOWORD(lParam);
	WindowHeight = HIWORD(lParam);

	if (WindowHeight == 0)
		return;

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof(d3dpp) );
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

	CleanupResources();

	if (g_pd3dDevice->Reset(&d3dpp) != D3D_OK)
	{
		printf("Error resetting device.");
		PostQuitMessage(1);
		return;
	}

	InitD3D(hWnd);
	InitGeometry();
	return;
}

//-----------------------------------------------------------------------------
// Name: OnKeyDown()
// Desc: Callback function called when a keboard key is pressed
//-----------------------------------------------------------------------------
void OnKeyDown(WPARAM wParam)
{
	switch (wParam)
	{
	case VK_DOWN:
		printf("Down pressed.\n"); 
		if (WireFrame > 0)
			WireFrame--; 	
		break;
	case VK_LEFT:
		printf("Left pressed.\n");
		break;
	case VK_RIGHT:
		printf("Right pressed.\n");
		break;
	case VK_UP:
		printf("Up pressed.\n"); 
		if (WireFrame < MaxFrame)
			WireFrame++; 
		break;
	case VK_TAB:
		if (!DXSniffer::Instance()->m_bPrintToConsole)
			DXSniffer::Instance()->m_bPrintToConsole = !DXSniffer::Instance()->m_bPrintToConsole;
		break;
	case VK_SPACE:
		DXSniffer::Instance()->CreateAlternativeView();
		break;
	}
	return;
}

//-----------------------------------------------------------------------------
// Name: OnMouseWheel()
// Desc: Callback function called when the mouse's wheel is used
//-----------------------------------------------------------------------------
void OnMouseWheel(WPARAM wParam)
{
	int x = GET_WHEEL_DELTA_WPARAM(wParam);
	if (x > 0)	// Wheel forward
	{
		camRadius -= 5;
		if (camRadius < 10)
			camRadius = 10;
	}
	else		// Wheel Backward
	{
		camRadius += 5;
		if (camRadius > 200)
			camRadius = 200;
	}
#ifdef DEBUGMODE
	printf("\nWheel delta is %d.", x);
#endif
	return;
}
//-----------------------------------------------------------------------------
// Name: OnMouseMove()
// Desc: Callback function called when the mouse moves over the rendering window
//-----------------------------------------------------------------------------
void OnMouseMove(WPARAM wParam, LPARAM lParam)
{
	prevMouseX = mouseX;
	prevMouseY = mouseY;
	int x = mouseX = LOWORD(lParam);
	int y = mouseY = HIWORD(lParam);

#ifdef DEBUGMODE
	printf("\nMouse Move Detected: %d, %d." ,x, y);
#endif

	switch(wParam)
	{
	case MK_LBUTTON:
		RotateCamera();
#ifdef DEBUGMODE
		printf("\nLeft button is pressed. ");
#endif
		break;
	case MK_RBUTTON:
		MoveCamera();
#ifdef DEBUGMODE
		printf("\nRight button is pressed. ");
#endif
		break;
	}
	return;
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	switch( msg )
	{
	case WM_DESTROY:
		OnDestroy();
		break;

	case WM_SIZE:
		OnSize(hWnd, lParam);
		break;

	case WM_KEYDOWN:
		OnKeyDown(wParam);
		break;			

	case WM_MOUSEWHEEL:
		OnMouseWheel(wParam);
		break;

	case WM_MOUSEMOVE:
		OnMouseMove(wParam, lParam);
		break;
	}

	return DefWindowProc( hWnd, msg, wParam, lParam );
}

//-----------------------------------------------------------------------------
// Name: _tmain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
	// Register the window class
	WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
		GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
		L"DxSniffer Demo Scene", NULL };
	RegisterClassEx( &wc );

	// Create the application's window
	HWND hWnd = CreateWindow( L"DxSniffer Demo Scene", L"DxSniffer Demo Scene",
		WS_OVERLAPPEDWINDOW, 100, 100, 600, 600,
		NULL, NULL, wc.hInstance, NULL );

	// Initialize Direct3D
	if( SUCCEEDED( InitD3D( hWnd ) ) )
	{
		// Create the geometry
		if( SUCCEEDED( InitGeometry() ) )
		{
			// Show the window
			ShowWindow( hWnd, SW_SHOWDEFAULT );
			UpdateWindow( hWnd );

			// Enter the message loop
			MSG msg;
			ZeroMemory( &msg, sizeof(msg) );
			while( msg.message!=WM_QUIT )
			{
				if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
				{
					TranslateMessage( &msg );
					DispatchMessage( &msg );
				}
				else
				{
					Render();
				}
			}
		}
	}

	Cleanup();
	printf ("\nDone. Exiting...");
	UnregisterClass( L"DxSniffer Demo Scene", wc.hInstance );
	return 0;
}

